package com.atguigu.service.impl;

import com.atguigu.constant.RedisConst;
import com.atguigu.entity.PrepareSeckillOrder;
import com.atguigu.entity.SeckillProduct;
import com.atguigu.entity.UserSeckillSkuInfo;
import com.atguigu.mapper.SeckillProductMapper;
import com.atguigu.result.RetVal;
import com.atguigu.result.RetValCodeEnum;
import com.atguigu.service.SeckillProductService;
import com.atguigu.util.MD5;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author fumeng
 * @since 2021-11-19
 */
@Service
public class SeckillProductServiceImpl extends ServiceImpl<SeckillProductMapper, SeckillProduct> implements SeckillProductService {

    @Autowired
    RedisTemplate redisTemplate;

    //秒杀的商品详情
    @Override
    public SeckillProduct getSeckillProductFromRedis(Long skuId) {
        return (SeckillProduct) redisTemplate.opsForHash().get(RedisConst.SECKILL_PRODUCT, skuId.toString());

    }

    //预下单
    @Override
    public void prepareSeckill(UserSeckillSkuInfo userSeckillSkuInfo) {
        Long skuId = userSeckillSkuInfo.getSkuId();
        String userId = userSeckillSkuInfo.getUserId();
        //1.效验秒杀状态位
        String state = (String)redisTemplate.opsForValue().get(RedisConst.SECKILL_STATE_PREFIX + skuId);
        //可以返回一个信息给页面调用方 ,商品以售罄
        if (RedisConst.CAN_NOT_SECKILL.equals(state)) {
            return;
        }
        //2.判断是否已经加入过，把用户抢购的订单放到缓存
        boolean flag=redisTemplate.opsForValue().setIfAbsent(RedisConst.PREPARE_SECKILL_USERID_SKUID +":"+userId+":"+
                userId,skuId,RedisConst.PREPARE_SECKILL_LOCK_TIME, TimeUnit.SECONDS);

        //true代表之前没有放入预订单，false代表已经放入
        if (!flag){
            //以放入
            return;
        }
        //3.效验库存是否还有库存，并在redis减库存
        String  stockSkuId = (String)redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).rightPop();
        //为空，没有库存
        if (StringUtils.isEmpty(stockSkuId)){
            //没有库存需要更新秒杀状态位
            redisTemplate.convertAndSend(RedisConst.PREPARE_PUB_SUB_SECKILL,skuId+":"+RedisConst.CAN_NOT_SECKILL);
            return;
        }
        //4.生成临时订单存储在redis
        PrepareSeckillOrder prepareSeckillOrder = new PrepareSeckillOrder();
        prepareSeckillOrder.setBuyNum(1);
        prepareSeckillOrder.setUserId(userId);
        SeckillProduct seckillProduct = getSeckillProductFromRedis(skuId);
        prepareSeckillOrder.setSeckillProduct(seckillProduct);
        //设置订单码
        prepareSeckillOrder.setPrepareOrderCode(MD5.encrypt(userId+skuId));
        //存入redis
        redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).put(userId,prepareSeckillOrder);
        //5.更新库存量
        updateSeckillStockCount(skuId);
    }



    //更新库存量
    private void updateSeckillStockCount(Long skuId) {
        //锁定库存量=总的数量-剩余的队列个数
        //剩余的库存个数
        Long size = redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).size();
        //更新频次
        //if (size%2==0){
            SeckillProduct seckillProduct = getSeckillProductFromRedis(skuId);
            Integer num = seckillProduct.getNum();
            int leftCountInt = Integer.parseInt(size + "");
            int stockCount= num-leftCountInt;
            seckillProduct.setStockCount(stockCount);
            //更新数据库是为了持久化，防止数据丢失
            baseMapper.updateById(seckillProduct);
            //更新redis里面的已售商品信息
            redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).put(skuId.toString(),seckillProduct);

        //}

    }

    //判断是否有抢购资格
    @Override
    public RetVal hasQualified(Long skuId, String userId) {
        //1.预下单中有用户信息，就代表有资格
        Boolean isExist = redisTemplate.hasKey(RedisConst.PREPARE_SECKILL_USERID_SKUID + ":"+userId+":"+
                userId);
        if (isExist) {
            //代表有订单，取出订单
            PrepareSeckillOrder prepareSeckillOrder = (PrepareSeckillOrder)redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).get(userId);

            if(prepareSeckillOrder!=null){
                return RetVal.build(prepareSeckillOrder, RetValCodeEnum.PREPARE_SECKILL_SUCCESS);
            }
        }
        //2.接着上一步 用户已经下过订单 (此处要演示需要重复购买相同的商品才能走这里的代码)
        String orderId = (String) redisTemplate.boundHashOps(RedisConst.BOUGHT_SECKILL_USER_ORDER).get(userId);
        if (!StringUtils.isEmpty(orderId)){
            return RetVal.build(orderId, RetValCodeEnum.SECKILL_ORDER_SUCCESS);
        }
        //其他情况就是排队中
        return RetVal.build(null, RetValCodeEnum.SECKILL_RUN);

    }
}
